package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.model.user.UserAddress;
import com.atguigu.gmall.user.clinet.UserFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.security.PublicKey;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods> implements SeckillGoodsService {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserFeignClient userFeignClient;


    @Override
    public List<SeckillGoods> getAllSeckillGoods() {
        HashOperations hashOperations = redisTemplate.opsForHash();
        String key = RedisConst.SECKILL_GOODS;
        List<SeckillGoods> seckillGoodsList = hashOperations.values(key);
        return seckillGoodsList;
    }

    @Override
    public SeckillGoods getSeckillGoodsBySkuId(Long skuId) {
        HashOperations hashOperations = redisTemplate.opsForHash();
        String key = RedisConst.SECKILL_GOODS;
        SeckillGoods seckillGoods = (SeckillGoods) hashOperations.get(key, skuId.toString());
        return seckillGoods;

    }

    @Override
    public String getCode(String skuId, String userId) {
        HashOperations hashOperations = redisTemplate.opsForHash();
        String key = RedisConst.SECKILL_GOODS;
        SeckillGoods seckillGoods = (SeckillGoods) hashOperations.get(key, skuId.toString());
        if (seckillGoods == null) {
            Result.fail().message("数据发生错误 skuId=" + skuId);
        }
        Date startTime = seckillGoods.getStartTime();
        Date endTime = seckillGoods.getEndTime();
        Date curDate = new Date();
        if (DateUtil.dateCompare(startTime, curDate) && DateUtil.dateCompare(curDate, endTime)) {
            String encrypt = MD5.encrypt(userId);
            return encrypt;
        }
        return null;
    }

    @Override
    public void preSeckillGoodsOrder(UserRecode userRecode) {
        String userId = userRecode.getUserId();
        Long skuId = userRecode.getSkuId();


        //检验状态位
        Object status = CacheHelper.get(skuId.toString());
        if ("0".equals(status)) {
            return;
        }

        //防止重复购买
        String unRepeat = RedisConst.SECKILL_USER + userId + ":" + skuId;
        Boolean redisUnRepeat = redisTemplate.opsForValue().setIfAbsent(unRepeat, UUID.randomUUID(), RedisConst.SECKILL__TIMEOUT, TimeUnit.SECONDS);
        if (!redisUnRepeat) {
            return;
        }

        //减库存
        Long increment = redisTemplate.opsForHash().increment(RedisConst.SECKILL_SALE_PRODUCTED, skuId.toString(), -1);
        if (increment == 0) {
            redisTemplate.convertAndSend("seckillpush",skuId+":0");
        }

        SeckillGoods seckillGoodsBySkuId = getSeckillGoodsBySkuId(skuId);
        seckillGoodsBySkuId.setStockCount(increment.intValue());

        String orderStr = UUID.randomUUID() + userId + skuId;
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userId);
        orderRecode.setSeckillGoods(seckillGoodsBySkuId);
        orderRecode.setNum(1);
        orderRecode.setOrderStr(orderStr);

        redisTemplate.opsForHash().put(RedisConst.SECKILL_ORDERS, userId, orderRecode);

        seckillGoodsMapper.updateById(seckillGoodsBySkuId);
        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS, skuId.toString(), seckillGoodsBySkuId);
    }

    @Override
    public Map<String, Object> getOrderTradeData(String userId) {
        List<OrderRecode> orderRecodeList = (List<OrderRecode>) redisTemplate.opsForHash().get(RedisConst.SECKILL_ORDERS, userId);
        List<Map<String, Object>> orderDetailMapList = new ArrayList<>();
        for (OrderRecode orderRecode : orderRecodeList) {
            SeckillGoods seckillGoods = orderRecode.getSeckillGoods();
            String imgUrl = seckillGoods.getSkuDefaultImg();
            String skuName = seckillGoods.getSkuName();
            int orderPrice = (int) ((int) seckillGoods.getNum() * seckillGoods.getCostPrice().doubleValue());
            Integer skuNum = seckillGoods.getNum();

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("imgUrl", imgUrl);
            resultMap.put("skuName", skuName);
            resultMap.put("orderPrice", orderPrice);
            resultMap.put("skuNum", skuNum);
            orderDetailMapList.add(resultMap);
        }

        Integer totalNum = orderRecodeList.stream().map(orderRecode -> orderRecode.getNum())
                .reduce(0, (x, y) -> {
                    return x + y;
                });

        Integer totalAmount = orderDetailMapList.stream().map(orderDetailMap -> {
            return (int) orderDetailMap.get("orderPrice");
        }).reduce(0, (x, y) -> {
            return (x + y);
        });

        List<UserAddress> userAddressList = userFeignClient.getUserAddressList().getData();

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("detailArrayList", orderDetailMapList);
        resultMap.put("totalNum", totalNum);
        resultMap.put("totalAmount", totalAmount);
        resultMap.put("userAddressList", userAddressList);

        return resultMap;
    }
}
